/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 */

import type { Level, Logger } from 'log4js';

/**
 * log方法装饰器，将传入方法的参数中的bundleName匿名化
 */
function beforeAnonymizeBundleName(target: object, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: unknown[]) {
    const anonymizeArgs = messageBundleNameAnonymize(args);
    return originalMethod.apply(this, anonymizeArgs);
  };
  return descriptor;
}

/**
 * 将参数中的bundleName匿名化 hash处理，对象与数组则递归查询是否有bundleName字段
 * @param msg
 */
function messageBundleNameAnonymize(msg: any): any {
  if (typeof msg !== 'object') {
    return msg;
  }
  // 数组递归查询
  if (Array.isArray(msg)) {
    return msg.map((row, index) => {
      if (typeof row === 'object') {
        return messageBundleNameAnonymize(row);
      }
      return msg[index];
    });
  }
  if (typeof msg === 'object') {
    const result: { [key: string]: any } = {};
    const keys = Object.keys(msg);
    keys.forEach((key) => {
      // bundleName hash处理
      if (key === 'bundleName' && typeof msg[key] === 'string') {
        const str = msg[key];
        result[key] = str ? `${str[0]}***${str[str.length - 1]}` : '*****';
      } else if (typeof msg[key] === 'object') {
        // 对象递归
        result[key] = messageBundleNameAnonymize(msg[key]);
      } else {
        result[key] = msg[key];
      }
    });
    return result;
  }
  return msg;
}

/**
 * 替换打印内容中的bundleName
 * 若此函数涉及到大对象，需要使用者考虑下性能问题
 * @param msg 打印内容
 * @param bundleName bundleName
 * @param regExp 根据bundleName生成的正则
 */
export function replaceBundleName(msg: any, bundleName: string, regExp?: RegExp): any {
  if (!bundleName?.length) {
    return msg;
  }
  if (!regExp) {
    regExp = new RegExp(bundleName, 'ig');
  }
  if (typeof msg === 'string' && regExp.test(msg)) {
    return msg.replace(regExp, ($1:string) => `${$1[0]}***${$1[$1.length - 1]}`);
  }
  if (Array.isArray(msg)) {
    return msg.map(item => replaceBundleName(item, bundleName, regExp));
  }
  if (typeof msg === 'object') {
    const keys = Object.keys(msg);
    return keys.reduce((result, key) => {
      return { ...result, [key]: replaceBundleName(msg[key], bundleName, regExp) };
    }, {});
  }
  return msg;
}
export class FileLogger {
  protected readonly fileLogger: Logger;

  constructor(logger: Logger) {
    this.fileLogger = logger;
  }

  @beforeAnonymizeBundleName
  debug(message: any, ...args: any[]) {
    this.fileLogger.debug(message, ...args);
    return [message, ...args];
  }

  @beforeAnonymizeBundleName
  log(level: Level | string, ...args: unknown[]) {
    this.fileLogger.log(level, ...args);
  }

  @beforeAnonymizeBundleName
  warn(message: any, ...args: any[]) {
    this.fileLogger.warn(message, ...args);
  }

  @beforeAnonymizeBundleName
  info(message: any, ...args: any[]) {
    this.fileLogger.info(message, ...args);
  }

  @beforeAnonymizeBundleName
  error(message: any, ...args: any[]) {
    this.fileLogger.error(message, ...args);
  }
}
